package com.niiwoo.civet.mobile.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.niiwoo.asset.org.business.dto.request.QueryOpenAccountOrderReqDTO;
import com.niiwoo.asset.org.business.dto.response.QueryOpenAccountOrderRespDTO;
import com.niiwoo.asset.org.business.service.dubbo.OpenAccountDubboService;
import com.niiwoo.civet.account.service.AccountDubboService;
import com.niiwoo.civet.account.service.bankcard.BankCardDubboService;
import com.niiwoo.civet.mobile.util.ParameterValidator;
import com.niiwoo.civet.mobile.util.R360RedisService;
import com.niiwoo.civet.mobile.vo.common.LinkManInfoVO;
import com.niiwoo.civet.mobile.vo.request.UserIdentityRequestVo;
import com.niiwoo.civet.mobile.vo.request.user.*;
import com.niiwoo.civet.mobile.vo.response.PortraitAuthResponseVO;
import com.niiwoo.civet.mobile.vo.response.user.*;
import com.niiwoo.civet.trade.dto.common.LoanBusinessInfoDTO;
import com.niiwoo.civet.trade.dto.common.ProjectDTO;
import com.niiwoo.civet.trade.dto.common.PromptMsgConfigDTO;
import com.niiwoo.civet.trade.dto.response.OcrPortraitAuthConfigResponseDTO;
import com.niiwoo.civet.trade.dto.response.statisticsinfo.StatisticsInfoResponseDTO;
import com.niiwoo.civet.trade.enums.ProjectTypeEnum;
import com.niiwoo.civet.trade.enums.PromptMsgTypeEnum;
import com.niiwoo.civet.trade.enums.TradeConfigEnum;
import com.niiwoo.civet.trade.service.ProjectCommonDubboService;
import com.niiwoo.civet.trade.service.configure.PromptMsgConfigDubboService;
import com.niiwoo.civet.trade.service.configure.TradeConfigDubboService;
import com.niiwoo.civet.trade.service.loan.LoanBusinessDubboService;
import com.niiwoo.civet.trade.service.project.ProjectDubboService;
import com.niiwoo.civet.trade.service.statisticsinfo.StatisticsInfoDubboService;
import com.niiwoo.civet.user.constants.LoginAccountErrorCode;
import com.niiwoo.civet.user.dto.LinkManDubboInfoDTO;
import com.niiwoo.civet.user.dto.UserPersonalDubboInfoDTO;
import com.niiwoo.civet.user.dto.UserProfessionDubboInfoDTO;
import com.niiwoo.civet.user.dto.request.*;
import com.niiwoo.civet.user.dto.response.FacePlusPortraitAuthResponseDTO;
import com.niiwoo.civet.user.dto.response.LoanDataAuthenticationResponseDTO;
import com.niiwoo.civet.user.enums.*;
import com.niiwoo.civet.user.service.*;
import com.niiwoo.tripod.consumer.component.FileUploadHandler;
import com.niiwoo.tripod.consumer.properties.FileUploadProperties;
import com.niiwoo.tripod.consumer.util.EmojiFilter;
import com.niiwoo.tripod.face.auth.LinkFaceAuth;
import com.niiwoo.tripod.face.auth.LinkFaceAuthV2;
import com.niiwoo.tripod.face.auth.dto.LinkFaceMaskIdCardRespV2;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.web.annotation.AuthIgnore;
import com.niiwoo.tripod.web.util.PrincipalContext;
import com.niiwoo.tripod.web.vo.Empty;
import com.niiwoo.tripod.web.vo.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;

/**
 * @Description: 用户资料
 * @Author:LiJian
 * @Date:2017/10/11
 */
@Slf4j
@RestController
@RequestMapping("/userData")
@Api(tags = "用户资料(李健)", description = "/userData")
public class UserDataController {
    @Reference(version = "1.0.0")
    private UserStatusDubboService userStatusDubboService;
    @Reference(version = "1.0.0")
    private UserImageFileDubboService userImageFileDubboService;
    @Reference(version = "1.0.0")
    private FacePlusPortraitAuthDubboService facePlusPortraitAuthDubboService;
    @Reference(version = "1.0.0")
    private UserDataDubboService userDataDubboService;
    @Reference(version = "1.0.0")
    private UserIdentityDubboService userIdentityDubboService;
    @Reference(version = "1.0.0")
    private TradeConfigDubboService tradeConfigDubboService;
    @Reference(version = "1.0.0")
    private PortraitAuthDubboService portraitAuthDubboService;
    @Reference(version = "1.0.0")
    private AccountDubboService accountDubboService;
    @Reference(version = "1.0.0")
    private ProjectCommonDubboService projectCommonDubboService;
    @Reference(version = "1.0.0")
    private UserBasicInfoDubboService userBasicInfoDubboService;
    @Reference(version = "1.0.0")
    private BankCardDubboService bankCardDubboService;
    @Reference(version = "1.0.0")
    private StatisticsInfoDubboService statisticsInfoDubboService;
    @Reference(version = "1.0.0")
    private LoanBusinessDubboService loanBusinessDubboService;
    @Reference(version = "1.0.0")
    private OpenAccountDubboService openAccountDubboService;
    @Reference(version = "1.0.0")
    private OrganizationDubboService organizationDubboService;
    @Reference(version = "1.0.0")
    private ProjectDubboService projectDubboService;
    @Reference(version = "1.0.0")
    private PromptMsgConfigDubboService promptMsgConfigDubboService;

    @Autowired
    R360RedisService r360RedisService;
    @Autowired
    LinkFaceAuth linkFaceAuth;

    @Autowired
    LinkFaceAuthV2 linkFaceAuthV2;

    @Autowired
    FileUploadHandler fileUploadHandler;


    @PostMapping("/userDataInfo")
    @ApiOperation("用户信息查询--个人信息+职业信息")
    public Result<UserDataInfoResponseVO> userDataInfo() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("userDataInfo.userId={}", userId);

        UserDataInfoResponseVO responseVO = new UserDataInfoResponseVO();
        UserPersonalDubboInfoDTO userPersonalDubboInfoDTO = userDataDubboService.userPersonalInfo(userId);
        UserProfessionDubboInfoDTO userProfessionDubboInfoDTO = userDataDubboService.userProfessionInfo(userId);

        if (userPersonalDubboInfoDTO != null) {
            String userPersonalInfoJSONString = JSON.toJSONString(userPersonalDubboInfoDTO);
            UserPersonalResponseVO userPersonalInfo = JSON.parseObject(userPersonalInfoJSONString, UserPersonalResponseVO.class);
            this.livingAddrDeal(userPersonalInfo);
            responseVO.setUserPersonalInfo(userPersonalInfo);
        }

        if (userProfessionDubboInfoDTO != null) {
            UserProfessionResponseVO userProfessionInfo = new UserProfessionResponseVO();
            BeanUtils.copyProperties(userProfessionDubboInfoDTO, userProfessionInfo);
            this.companyAddrDeal(userProfessionInfo);
            responseVO.setUserProfessionInfo(userProfessionInfo);
        }

        if(userPersonalDubboInfoDTO == null && userProfessionDubboInfoDTO != null) {
            UserPersonalResponseVO userPersonalInfo = new UserPersonalResponseVO();
            userPersonalInfo.setEduIsAllowUpdate(Byte.valueOf("1"));
            userPersonalInfo.setEducationAuthStatus(Byte.valueOf("0"));
            responseVO.setUserPersonalInfo(userPersonalInfo);
        }

        responseVO.setScrollingHint(this.getScrollingHint());
        log.info("userDataInfo.userId={},responseVO={} end", userId, JSON.toJSONString(responseVO));
        return Result.with(responseVO);
    }

    @PostMapping("/userPersonalInfo")
    @ApiOperation("用户个人信息--基本信息")
    public Result<UserPersonalResponseVO> userPersonalInfo() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("userPersonalInfo userId={}", userId);

        UserPersonalDubboInfoDTO userPersonalDubboInfoDTO = userDataDubboService.userPersonalInfo(userId);
        UserPersonalResponseVO userPersonalResponseVO = new UserPersonalResponseVO();
        if (userPersonalDubboInfoDTO != null) {
            BeanUtils.copyProperties(userPersonalDubboInfoDTO, userPersonalResponseVO);
            this.livingAddrDeal(userPersonalResponseVO);
        }
        log.info("userPersonalInfo end responseVO={}", JSON.toJSONString(userPersonalResponseVO));
        return Result.with(userPersonalResponseVO);
    }

    @PostMapping("/userProfessionInfo")
    @ApiOperation("用户个人信息--职业信息")
    public Result<UserProfessionResponseVO> userProfessionInfo() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("userProfessionInfo userId={}", userId);

        UserProfessionDubboInfoDTO userProfessionDubboInfoDTO = userDataDubboService.userProfessionInfo(userId);
        UserProfessionResponseVO userProfessionResponseVO = new UserProfessionResponseVO();
        if (userProfessionDubboInfoDTO != null) {
            BeanUtils.copyProperties(userProfessionDubboInfoDTO, userProfessionResponseVO);
            this.companyAddrDeal(userProfessionResponseVO);
        }

        log.info("userProfessionInfo end responseVO={}", JSON.toJSONString(userProfessionResponseVO));
        return Result.with(userProfessionResponseVO);
    }

    private void livingAddrDeal(UserPersonalResponseVO userPersonalInfo){
        if(userPersonalInfo==null){
            return;
        }
        if(!StringUtils.hasText(userPersonalInfo.getLivingProvince())
                || !StringUtils.hasText(userPersonalInfo.getLivingCity())
                || !StringUtils.hasText(userPersonalInfo.getLivingArea())){
            userPersonalInfo.setLivingProvince(null);
            userPersonalInfo.setLivingCity(null);
            userPersonalInfo.setLivingArea(null);
            userPersonalInfo.setLivingAddress(null);
        }
    }

    private void companyAddrDeal(UserProfessionResponseVO userProfessionInfo){
        if(userProfessionInfo==null){
            return;
        }
        if(!StringUtils.hasText(userProfessionInfo.getCompanyProvince())
                || !StringUtils.hasText(userProfessionInfo.getCompanyCity())
                || !StringUtils.hasText(userProfessionInfo.getCompanyArea())){
            userProfessionInfo.setCompanyProvince(null);
            userProfessionInfo.setCompanyCity(null);
            userProfessionInfo.setCompanyArea(null);
            userProfessionInfo.setCompanyAddress(null);
        }
    }

    /**
     * 获取滚动文案
     */
    private List<String> getScrollingHint(){
        List<String> scrollingHintList = new ArrayList<>();
        Map<String,String> tradeConfigMap = tradeConfigDubboService.selectTradeConfigByEmuns(Arrays.asList(
                TradeConfigEnum.LOANSCROLLMSGSTATUS,
                TradeConfigEnum.LOANSCROLLMSG
        ));
        String loanScrollMsg = tradeConfigMap.get(TradeConfigEnum.LOANSCROLLMSG.getConfigKey()); // 借款个人信息页面滚动文案开关配置 0：关闭 1：开启
        String loanScrollMsgStatus = tradeConfigMap.get(TradeConfigEnum.LOANSCROLLMSGSTATUS.getConfigKey()); // 借款个人信息页面滚动文案开关配置 0：关闭 1：开启
        try{
            if(loanScrollMsgStatus.equals("1")){
                StatisticsInfoResponseDTO statisticsInfo = statisticsInfoDubboService.queryStatisticsInfo();
                if(statisticsInfo != null){
                    String registerUserCount = ParameterValidator.getYiWan(statisticsInfo.getRegisterUserCount());
                    String cumulativeTradeAmount = ParameterValidator.getYiWan(statisticsInfo.getCumulativeTradeAmount());
                    loanScrollMsg = String.format(loanScrollMsg, registerUserCount, cumulativeTradeAmount);
                    scrollingHintList = Arrays.asList(loanScrollMsg.split("\\|"));
                }
            }
        }catch (Exception e){
            log.error("UserDataController.getScrollingHint e={}", e.getMessage());
        }
        return scrollingHintList;
    }



    @PostMapping("/postUserPersonalInfo")
    @ApiOperation("用户个人信息--提交基本信息")
    public Empty postUserPersonalInfo(@RequestBody @Valid UserPersonalRequestVO userPersonalRequestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("postUserPersonalInfo.userId={},userPersonalRequestVO={}", userId, JSON.toJSONString(userPersonalRequestVO));

        UserPersonalDubboInfoDTO userPersonalDubboInfoDTO = new UserPersonalDubboInfoDTO();
        if(!EmojiFilter.containsEmoji(userPersonalRequestVO.getLivingAddress())){
            throw new BizException("USR10038");
        }
        BeanUtils.copyProperties(userPersonalRequestVO, userPersonalDubboInfoDTO);
        userPersonalDubboInfoDTO.setUserId(userId);
        userPersonalDubboInfoDTO.setUserInfoUpdateOperTypeEnum(UserInfoUpdateOperTypeEnum.APP_USER);

        //如果婚姻状况不存在，则设置为“其它”
        Optional<UserPersonalEnum.UserMaritalStatusEnum> userMaritalStatusEnumOpt = Optional
                .ofNullable(UserPersonalEnum.UserMaritalStatusEnum.getByLevel(userPersonalRequestVO.getMaritalStatus()));
        userPersonalDubboInfoDTO.setMaritalStatus(userMaritalStatusEnumOpt
                .map(userMaritalStatusEnum -> userMaritalStatusEnum.getStatus()).orElse(UserPersonalEnum.UserMaritalStatusEnum.OTHER.getStatus()));
        userPersonalDubboInfoDTO.setLinkManInfoList(this.initLinkManInfoList(Optional.ofNullable(userPersonalRequestVO.getLinkManInfoList())));
        userDataDubboService.saveOrUpdateUserPersonalInfo(userPersonalDubboInfoDTO);

        return Empty.getInstance();
    }

    //初始化联系人信息列表
    private List<LinkManDubboInfoDTO> initLinkManInfoList(Optional<List<LinkManInfoVO>> linkManInfoVOListOpt) {
        return linkManInfoVOListOpt.map(linkManInfoVOList -> {
            List<LinkManDubboInfoDTO> linkManInfoList = new ArrayList<>();
            linkManInfoVOList.forEach(linkManInfoVO -> {
                LinkManDubboInfoDTO linkManDubboInfoDTO = new LinkManDubboInfoDTO();
                BeanUtils.copyProperties(linkManInfoVO, linkManDubboInfoDTO);
                linkManInfoList.add(linkManDubboInfoDTO);
            });
            return linkManInfoList;
        }).orElse(null);
    }

    @PostMapping("/postUserProfessionInfo")
    @ApiOperation("用户个人信息--提交职业信息")
    public Empty postUserProfessionInfo(@RequestBody @Valid UserProfessionRequestVO userProfessionRequestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("postUserProfessionInfo.userId={},userProfessionRequestVO={}", userId, JSON.toJSONString(userProfessionRequestVO));

        UserProfessionDubboInfoDTO userProfessionDubboInfoDTO = new UserProfessionDubboInfoDTO();
        if(!EmojiFilter.containsEmoji(userProfessionRequestVO.getCompanyAddress())){
            throw new BizException("USR10038");
        }
        userProfessionDubboInfoDTO.setUserId(userId);
        BeanUtils.copyProperties(userProfessionRequestVO, userProfessionDubboInfoDTO);
        userProfessionDubboInfoDTO.setUserInfoUpdateOperTypeEnum(UserInfoUpdateOperTypeEnum.APP_USER);
        userDataDubboService.saveOrUpdateUserProfessionInfo(userProfessionDubboInfoDTO);

        log.info("postUserProfessionInfo.userId={} end", userId);
        return Empty.getInstance();
    }

    @PostMapping("/userIdentityInfo/h5")
    @ApiOperation("用户身份信息h5")
    @AuthIgnore
    public Result<UserIdentityResponseVO> userIdentityInfoH5(@RequestBody UserIdentityRequestVo requestVo) {
        String userId;
        if (requestVo.getChannel() == null) {
            userId = r360RedisService.verifyTokenAndGetUserId(requestVo.getToken());
        } else {
            userId = r360RedisService.verifyTokenAndGetUserId(requestVo.getToken(), requestVo.getChannel());
        }
        OCRStatusInfoRequestDTO statusRequest = new OCRStatusInfoRequestDTO();
        statusRequest.setUserId(userId);
        UserIdentityResponseVO responseVO = new UserIdentityResponseVO();
        // 查询OCR相关状态信息
        Optional.ofNullable(userIdentityDubboService.getIdentityAndStatusAndImage(statusRequest))
                .ifPresent(ocrStatusResponseDTO -> {
                    responseVO.setIdCard(ocrStatusResponseDTO.getIdCard());
                    responseVO.setName(ocrStatusResponseDTO.getName());
                    responseVO.setSex(Optional.ofNullable(ocrStatusResponseDTO.getSex()).map(UserIdentitySexEnum::getValue).orElse(null));
                    responseVO.setNation(ocrStatusResponseDTO.getNation());
                    responseVO.setBirthday(ocrStatusResponseDTO.getBirthday());
                    responseVO.setStartDate(ocrStatusResponseDTO.getStartDate());
                    responseVO.setEndDate(ocrStatusResponseDTO.getEndDate());
                    responseVO.setAddress(ocrStatusResponseDTO.getAddress());
                    responseVO.setBackPhotoUrl(ocrStatusResponseDTO.getBackPhotoUrl());
                    responseVO.setFrontPhotoUrl(ocrStatusResponseDTO.getFrontPhotoUrl());
                    responseVO.setHandPhotoUrl(ocrStatusResponseDTO.getHandPhotoUrl());
                    if (ocrStatusResponseDTO.getIdCardExpiredStatus() != null) {
                        responseVO.setIdCardExpiredStatus(ocrStatusResponseDTO.getIdCardExpiredStatus().getStatus());
                    }
                    responseVO.setOcrStatus(ocrStatusResponseDTO.getOcrStatus().getStatus());
                    responseVO.setPortraitStatus(ocrStatusResponseDTO.getPortraitAuthStatus().getStatus());
                    responseVO.setTwoFactorStatus(ocrStatusResponseDTO.getRealNameAuthStatus().getStatus());
                    responseVO.setLastOCRIdCardChannel(ocrStatusResponseDTO.getLastOCRChannel().getValue());
                    responseVO.setBackPhotoId(ocrStatusResponseDTO.getBackPhotoId());
                    responseVO.setFrontPhotoId(ocrStatusResponseDTO.getFrontPhotoId());
                    responseVO.setHandPhotoId(ocrStatusResponseDTO.getHandPhotoId());
                    responseVO.setSigningAuthority(ocrStatusResponseDTO.getSigningAuthority());
                    responseVO.setIdentityAuthForbidStatus(ocrStatusResponseDTO.getIsForbidIdentityAuth() ? (byte) 1 : (byte) 0);
                });

        // 第三方渠道为机构极速借
        if(Objects.equals(R360RedisService.ThirdPart.ORG.getChannel(), requestVo.getChannel())) {
            QueryOpenAccountOrderReqDTO queryOpenAccountOrderReqDTO=new QueryOpenAccountOrderReqDTO();
            queryOpenAccountOrderReqDTO.setOrgId(organizationDubboService.loadValidOrgId(requestVo.getOrgCode()));
            queryOpenAccountOrderReqDTO.setUserId(userId);
            QueryOpenAccountOrderRespDTO queryOpenAccountOrderRespDTO = openAccountDubboService.queryOpenAccountOrder(queryOpenAccountOrderReqDTO);
            responseVO.setBankCardNo(queryOpenAccountOrderRespDTO.getBorrowerBankCard());
            responseVO.setBankCardMobileNo(queryOpenAccountOrderRespDTO.getBorrowerMobile());
            responseVO.setBankCode(queryOpenAccountOrderRespDTO.getBorrowerBankCode());
        }else{
            try {
                Optional.of(bankCardDubboService.getUserBankCardInfo(userId))
                        .ifPresent(b -> {
                            responseVO.setBankCardNo(b.getBankAccountNo());
                            responseVO.setBankCardMobileNo(b.getMobileNo());
                            responseVO.setBankCode(b.getBankCode());
                        });
            } catch (Exception e) {
                log.info("找不到银行卡信息, userId={}", userId);
            }
        }

        return Result.with(responseVO);
    }

    @PostMapping("/userIdentityInfo")
    @ApiOperation("用户身份信息")
    public Result<UserIdentityResponseVO> userIdentityInfo() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        UserIdentityResponseVO responseVO = new UserIdentityResponseVO();
        // 查询OCR通道配置, 是否开启OCR
        OcrPortraitAuthConfigResponseDTO configResponseDTO = Optional.ofNullable(tradeConfigDubboService.queryOcrPortraitConfig())
                .orElseThrow(() -> new BizException(LoginAccountErrorCode.LOAD_OCR_CONFIG_FAIL));
        OCRChannelEnum channel = Objects.equals(configResponseDTO.getOcrScanIdCardSwitch(), "1") &&
                Objects.equals(configResponseDTO.getPortraitAuthSwitch(), "1") &&
                Arrays.asList(configResponseDTO.getOcrScanIdCardDevice().split(",")).contains("1") ?
                OCRChannelEnum.FACE : OCRChannelEnum.EMPTY;
        responseVO.setOrcIdCardChannel(channel.getValue());
        OCRBankSwitchEnum switchEnum = Objects.equals(configResponseDTO.getOcrScanBankCardSwitch(), "1") &&
                Arrays.asList(configResponseDTO.getOcrScanBankCardDevice().split(",")).contains("1") ?
                OCRBankSwitchEnum.ON : OCRBankSwitchEnum.OFF;
        responseVO.setOrcBankCardChannel(switchEnum.getValue());
        OCRStatusInfoRequestDTO statusRequest = new OCRStatusInfoRequestDTO();
        statusRequest.setUserId(userId);
        // 查询OCR相关状态信息
        Optional.ofNullable(userIdentityDubboService.getIdentityAndStatusAndImage(statusRequest))
                .ifPresent(ocrStatusResponseDTO -> {
                    responseVO.setIdCard(ocrStatusResponseDTO.getIdCard());
                    responseVO.setName(ocrStatusResponseDTO.getName());
                    responseVO.setSex(Optional.ofNullable(ocrStatusResponseDTO.getSex()).map(UserIdentitySexEnum::getValue).orElse(null));
                    responseVO.setNation(ocrStatusResponseDTO.getNation());
                    responseVO.setBirthday(ocrStatusResponseDTO.getBirthday());
                    responseVO.setStartDate(ocrStatusResponseDTO.getStartDate());
                    responseVO.setEndDate(ocrStatusResponseDTO.getEndDate());
                    responseVO.setAddress(ocrStatusResponseDTO.getAddress());
                    responseVO.setBackPhotoUrl(ocrStatusResponseDTO.getBackPhotoUrl());
                    responseVO.setFrontPhotoUrl(ocrStatusResponseDTO.getFrontPhotoUrl());
                    responseVO.setHandPhotoUrl(ocrStatusResponseDTO.getHandPhotoUrl());
                    if (ocrStatusResponseDTO.getIdCardExpiredStatus() != null) {
                        responseVO.setIdCardExpiredStatus(ocrStatusResponseDTO.getIdCardExpiredStatus().getStatus());
                    }
                    responseVO.setOcrStatus(ocrStatusResponseDTO.getOcrStatus().getStatus());
                    responseVO.setPortraitStatus(ocrStatusResponseDTO.getPortraitAuthStatus().getStatus());
                    responseVO.setTwoFactorStatus(ocrStatusResponseDTO.getRealNameAuthStatus().getStatus());
                    responseVO.setLastOCRIdCardChannel(ocrStatusResponseDTO.getLastOCRChannel().getValue());
                    responseVO.setBackPhotoId(ocrStatusResponseDTO.getBackPhotoId());
                    responseVO.setFrontPhotoId(ocrStatusResponseDTO.getFrontPhotoId());
                    responseVO.setHandPhotoId(ocrStatusResponseDTO.getHandPhotoId());
                    responseVO.setSigningAuthority(ocrStatusResponseDTO.getSigningAuthority());
                    responseVO.setIdentityAuthForbidStatus(ocrStatusResponseDTO.getIsForbidIdentityAuth() ? (byte) 1 : (byte) 0);
                });

        try {
            Optional.of(bankCardDubboService.getUserBankCardInfo(userId))
                    .ifPresent(b -> {
                        responseVO.setBankCardNo(b.getBankAccountNo());
                        responseVO.setBankCardMobileNo(b.getMobileNo());
                        responseVO.setBankCode(b.getBankCode());
                    });
        } catch (Exception e) {
            log.info("找不到银行卡信息, userId={}", userId);
        }

        return Result.with(responseVO);
    }

    @PostMapping("/userIdentityInfo/channel")
    @ApiOperation(value = "使用渠道OCR验证用户身份信息提交", notes = "OCR开启时调用")
    public Empty postUserIdentityInfoWithChannelAuth(@RequestBody @Valid UserIdentityWithChannelAuthRequestVO requestVO) {
        // 参数校验
        UserIdentitySexEnum sex = UserIdentitySexEnum.of(requestVO.getSex());
        if (sex == null) {
            throw new BizException(LoginAccountErrorCode.UNKNOWN_SEX);
        }
        if (!ParameterValidator.isChineseName(requestVO.getName())) {
            throw new BizException(LoginAccountErrorCode.NAME_FORMAT_ERROR);
        }
        OCRChannelEnum ocrChannel = OCRChannelEnum.of(requestVO.getOcrChannel());
        if (ocrChannel == null || ocrChannel == OCRChannelEnum.EMPTY) {
            throw new BizException(LoginAccountErrorCode.NOT_SUPPORT_OCR_CHANNEL);
        }
        boolean isDateValid = requestVO.getBirthday().before(requestVO.getStartDate()) && requestVO.getStartDate().before(requestVO.getEndDate());
        if (!isDateValid) {
            throw new BizException(LoginAccountErrorCode.OCR_IDENTITY_DATE_ERROR);
        }
        UserDataStatusEnum.IdCardExpiredStatus idCardExpiredStatus = UserDataStatusEnum.IdCardExpiredStatus.get(requestVO.getEndDate(), 30);
        if (idCardExpiredStatus == UserDataStatusEnum.IdCardExpiredStatus.EXPIRING) {
            throw new BizException(LoginAccountErrorCode.OCR_ID_CARD_EXPIRING);
        }
        if (idCardExpiredStatus == UserDataStatusEnum.IdCardExpiredStatus.EXPIRED) {
            throw new BizException(LoginAccountErrorCode.OCR_ID_CARD_EXPIRED);
        }
        if (requestVO.getBackPhotoId() == null && !StringUtils.hasText(requestVO.getBackPhotoByte())) {
            throw new BizException(LoginAccountErrorCode.MISS_ID_CARD_FRONT_IMAGE);
        }
        if (requestVO.getFrontPhotoId() == null && !StringUtils.hasText(requestVO.getFrontPhotoByte())) {
            throw new BizException(LoginAccountErrorCode.MISS_ID_CARD_BACK_IMAGE);
        }
        // 查询OCR渠道配置，必须是开启状态
        OcrPortraitAuthConfigResponseDTO configResponseDTO = Optional.ofNullable(tradeConfigDubboService.queryOcrPortraitConfig())
                .orElseThrow(() -> new BizException(LoginAccountErrorCode.LOAD_OCR_CONFIG_FAIL));
        boolean isEnableOCR = Objects.equals(configResponseDTO.getOcrScanIdCardSwitch(), "1") &&
                Objects.equals(configResponseDTO.getPortraitAuthSwitch(), "1") &&
                Arrays.asList(configResponseDTO.getOcrScanIdCardDevice().split(",")).contains("1");
        if (!isEnableOCR) {
            throw new BizException(LoginAccountErrorCode.OCR_UNAVAILABLE);
        }
        String userId = String.valueOf(PrincipalContext.getUserId());
        OCRAuthInfoRequestDTO dto = new OCRAuthInfoRequestDTO();
        dto.setFrontImage(generateOCRImageItem(requestVO.getFrontPhotoId(), requestVO.getFrontPhotoByte(), true));
        dto.setBackImage(generateOCRImageItem(requestVO.getBackPhotoId(), requestVO.getBackPhotoByte(), true));
        dto.setName(requestVO.getName());
        dto.setSex(sex);
        dto.setNation(requestVO.getNation());
        dto.setIdCard(requestVO.getIdCard());
        dto.setBirthday(requestVO.getBirthday());
        dto.setStartDate(requestVO.getStartDate());
        dto.setEndDate(requestVO.getEndDate());
        dto.setAddress(requestVO.getAddress());
        dto.setAddressCode(requestVO.getIdCard().substring(0, 6));
        dto.setSigningAuthority(requestVO.getSigningAuthority());
        dto.setOcrChannel(ocrChannel);
        dto.setUserId(userId);
        if (!userIdentityDubboService.saveAuthInfo(dto)) {
            throw new BizException(LoginAccountErrorCode.SAVE_OCR_INFO_ERROR);
        }
        return Empty.getInstance();
    }

    /**
     * 保存图片
     *
     * @param imageBase64Str 图片base64字符串
     */
    private OCRImageItemDTO generateOCRImageItem(Long imageId, String imageBase64Str, boolean isMask) {
        OCRImageItemDTO imageItemDTO = new OCRImageItemDTO();
        if (StringUtils.hasText(imageBase64Str)) {
            try {
                // 上传原图
                FileUploadProperties.FileUploadResult srcImage = fileUploadHandler.upload(imageBase64Str, true);
                // 打码略缩图
                imageItemDTO.setImgUrl(srcImage.getImageUrl());
                imageItemDTO.setImgThumbnailUrl(srcImage.getSmallImageUrl());
                // 调用商汤打码
                if (isMask) {
                    LinkFaceMaskIdCardRespV2 linkFaceMaskIdCardResp = linkFaceAuthV2.maskIdcard(Base64.decodeBase64(imageBase64Str), "", true, true, true, true, true, true).get();
                    if (org.apache.commons.lang3.StringUtils.isNotBlank(linkFaceMaskIdCardResp.getMaskedIdcard())) {
                        FileUploadProperties.FileUploadResult maskImage = fileUploadHandler.upload(linkFaceMaskIdCardResp.getMaskedIdcard(), true, "jpg");
                        imageItemDTO.setImgReleaseUrl(maskImage.getImageUrl());
                        imageItemDTO.setImgReleaseThumbnailUrl(maskImage.getSmallImageUrl());
                    }
                }
                return imageItemDTO;
            } catch (Exception e) {
                log.error("OCR图片保存失败", e);
                throw new BizException(LoginAccountErrorCode.UPLOAD_OCR_IMAGE_FAIL);
            }
        } else {
            imageItemDTO.setImageId(imageId);
        }
        return imageItemDTO;
    }

    @PostMapping("/userIdentityInfo/focus")
    @ApiOperation(value = "不使用渠道OCR验证用户身份信息提交", notes = "用户仅上传身份证正面照，反面照和手持照. OCR关闭时调用")
    public Empty postUserIdentityInfoWithOutChannelAuth(@RequestBody @Valid UserIdentityWithOutChannelAuthRequestVO requestVO) {
        if (requestVO.getBackPhotoId() == null && !StringUtils.hasText(requestVO.getBackPhotoByte())) {
            throw new BizException(LoginAccountErrorCode.MISS_ID_CARD_FRONT_IMAGE);
        }
        if (requestVO.getFrontPhotoId() == null && !StringUtils.hasText(requestVO.getFrontPhotoByte())) {
            throw new BizException(LoginAccountErrorCode.MISS_ID_CARD_BACK_IMAGE);
        }
        if (requestVO.getHandPhotoId() == null && !StringUtils.hasText(requestVO.getHandPhotoByte())) {
            throw new BizException(LoginAccountErrorCode.MISS_ID_CARD_HAND_IMAGE);
        }
        // 查询OCR渠道配置，必须是关闭状态
        OcrPortraitAuthConfigResponseDTO configResponseDTO = Optional.ofNullable(tradeConfigDubboService.queryOcrPortraitConfig())
                .orElseThrow(() -> new BizException(LoginAccountErrorCode.LOAD_OCR_CONFIG_FAIL));
        boolean isEnableOCR = Objects.equals(configResponseDTO.getOcrScanIdCardSwitch(), "1") &&
                Objects.equals(configResponseDTO.getPortraitAuthSwitch(), "1") &&
                Arrays.asList(configResponseDTO.getOcrScanIdCardDevice().split(",")).contains("1");
        if (isEnableOCR) {
            throw new BizException(LoginAccountErrorCode.OCR_AVAILABLE);
        }
        String userId = String.valueOf(PrincipalContext.getUserId());
        OCRNotAuthInfoRequestDTO dto = new OCRNotAuthInfoRequestDTO();
        dto.setUserId(userId);
        dto.setBackImage(generateOCRImageItem(requestVO.getBackPhotoId(), requestVO.getBackPhotoByte(), true));
        dto.setFrontImage(generateOCRImageItem(requestVO.getFrontPhotoId(), requestVO.getFrontPhotoByte(), true));
        dto.setHandImage(generateOCRImageItem(requestVO.getHandPhotoId(), requestVO.getHandPhotoByte(), false));
        if (!userIdentityDubboService.focusSaveAuthInfo(dto)) {
            throw new BizException(LoginAccountErrorCode.SAVE_OCR_INFO_ERROR);
        }
        return Empty.getInstance();
    }

    @PostMapping("/portraitAuthInfo")
    @ApiOperation("肖像认证信息")
    public Result<PortraitAuthConfigResponseDTO> portraitAuthInfo() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        // 查询肖像配置, 是否开启肖像认证
        OcrPortraitAuthConfigResponseDTO configResponseDTO = Optional.ofNullable(tradeConfigDubboService.queryOcrPortraitConfig())
                .orElseThrow(() -> new BizException(LoginAccountErrorCode.LOAD_OCR_CONFIG_FAIL));
        boolean isEnablePortraitAuth = Objects.equals(configResponseDTO.getOcrScanIdCardSwitch(), "1") &&
                Objects.equals(configResponseDTO.getPortraitAuthSwitch(), "1") &&
                Arrays.asList(configResponseDTO.getOcrScanIdCardDevice().split(",")).contains("1");
        if (!isEnablePortraitAuth) {
            throw new BizException(LoginAccountErrorCode.PORTRAIT_NOT_ENABLE);
        }
        PortraitAuthConfigResponseDTO responseDTO = new PortraitAuthConfigResponseDTO();
        responseDTO.setPortraitAuthChannel(PortraitChannelEnum.FACE_PLUS.getValue());
        responseDTO.setDetectBlink(Integer.valueOf(configResponseDTO.getPortraitAuthActionFacePlusDetectBlink()));
        responseDTO.setDetectOpenMouth(Integer.valueOf(configResponseDTO.getPortraitAuthActionFacePlusDetectOpenMouth()));
        responseDTO.setDetectShakeHead(Integer.valueOf(configResponseDTO.getPortraitAuthActionFacePlusDetectShakeHead()));
        responseDTO.setDetectNodHead(Integer.valueOf(configResponseDTO.getPortraitAuthActionFacePlusDetectNodHead()));
        Optional<portraitAuthStatusResponseDTO> statusInfoOpt = Optional.ofNullable(portraitAuthDubboService.getStatusInfo(userId));
        responseDTO.setLeftPortraitAuthTimes(statusInfoOpt.map(portraitAuthStatusResponseDTO::getLeftPortraitAuthTimes).orElse(0));
        responseDTO.setPortraitAuthTimesThreshold(statusInfoOpt.map(portraitAuthStatusResponseDTO::getPortraitAuthTimesThreshold).orElse(0));
        return Result.with(responseDTO);
    }

    @PostMapping("/portraitAuth")
    @ApiOperation("肖像认证")
    public Result<PortraitAuthResponseVO> portraitAuth(@RequestBody @Valid PortraitAuthRequestVO requestVO) {
        // 参数校验
        PortraitChannelEnum channel = PortraitChannelEnum.of(requestVO.getChannel());
        if (channel == null) {
            throw new BizException(LoginAccountErrorCode.NOT_SUPPORT_PORTRAIT_CHANNEL);
        }
        if (channel == PortraitChannelEnum.FACE_PLUS && !StringUtils.hasText(requestVO.getDelta())) {
            throw new BizException(LoginAccountErrorCode.FACE_PLUS_CHECK_NULL);
        }
        PortraitAuthClientType clientType = PortraitAuthClientType.of(requestVO.getClientType());
        if (clientType == null) {
            throw new BizException(LoginAccountErrorCode.DEVICE_TYPE_ERROR);
        }
        // 查询肖像配置, 是否开启肖像认证
        OcrPortraitAuthConfigResponseDTO configResponseDTO = Optional.ofNullable(tradeConfigDubboService.queryOcrPortraitConfig())
                .orElseThrow(() -> new BizException(LoginAccountErrorCode.LOAD_OCR_CONFIG_FAIL));
        boolean isEnablePortraitAuth = Objects.equals(configResponseDTO.getOcrScanIdCardSwitch(), "1") &&
                Objects.equals(configResponseDTO.getPortraitAuthSwitch(), "1") &&
                Arrays.asList(configResponseDTO.getPortraitAuthFacePlusDevice().split(",")).contains("1");
        if (!isEnablePortraitAuth) {
            throw new BizException(LoginAccountErrorCode.PORTRAIT_NOT_ENABLE);
        }
        String userId = String.valueOf(PrincipalContext.getUserId());
        // 查询肖像配置, 是否开启肖像认证
        PortraitAuthRequestDTO dto = new PortraitAuthRequestDTO();
        dto.setChannel(channel);
        dto.setUserId(userId);
        dto.setDelta(requestVO.getDelta());
        dto.setLiveImageUrl(fileUploadHandler.upload(requestVO.getLiveImageBase64(), false).getImageUrl());
        dto.setFacePlusEnvImageUrl(fileUploadHandler.upload(requestVO.getFacePlusEnvImageBase64(), false).getImageUrl());
        dto.setClientType(clientType);
        PortraitAuthResponseVO vo = new PortraitAuthResponseVO();
        Optional.ofNullable(portraitAuthDubboService.auth(dto)).ifPresent(d -> {
            vo.setPortraitAuthStatus(d.getPortraitAuthStatus().getStatus());
            vo.setLeftPortraitAuthTimes(d.getLeftPortraitAuthTimes());
        });

        return Result.with(vo);
    }


    /******************************** 5.1.5 新增 **********************************/

    @PostMapping("/portraitAuth2")
    @ApiOperation("肖像认证采集")
    public Result<PortraitAuthResponseVO> portraitAuth2(@RequestBody @Valid PortraitAuthRequestVO requestVO) {
        FacePlusPortraitAuthRequestDTO requestDTO = new FacePlusPortraitAuthRequestDTO();
        requestDTO.setUserId(PrincipalContext.getUserId());
        CountDownLatch latch = new CountDownLatch(3);
        // 上传face++活体照片
        CompletableFuture.supplyAsync(() -> fileUploadHandler.upload(requestVO.getLiveImageBase64(), false)).whenComplete((r, t) -> {
            try {
                if (t != null) {
                    log.error(String.format("上传face++活体照片, exception=%s", t.getMessage()), t);
                } else {
                    log.info("上传face++活体照片, result={}", JSON.toJSONString(r));
                    requestDTO.setLiveImageUrl(r.getImageUrl());
                }
            } finally {
                latch.countDown();
            }
        });
        // 上传face++对比照片
        CompletableFuture.supplyAsync(() -> fileUploadHandler.upload(requestVO.getFacePlusEnvImageBase64(), false)).whenComplete((r, t) -> {
            try {
                if (t != null) {
                    log.error(String.format("上传face++对比照片, exception=%s", t.getMessage()), t);
                } else {
                    log.info("上传face++对比照片, result={}", JSON.toJSONString(r));
                    requestDTO.setFacePlusEnvImageUrl(r.getImageUrl());
                }
            } finally {
                latch.countDown();
            }
        });
        // 上传face++校验字符串文件
        CompletableFuture.supplyAsync(() -> {
            try {
                return fileUploadHandler.upload(requestVO.getDelta().getBytes("UTF-8"), false, "txt");
            } catch (UnsupportedEncodingException e) {
                log.error("上传face++校验字符串文件，编码失败", e);
                throw new BizException(LoginAccountErrorCode.PORTRAIT_AUTH_UPLOAD_FILE_ERROR);
            }
        }).whenComplete((r, t) -> {
            try {
                if (t != null) {
                    log.error(String.format("上传face++对比照片, exception=%s", t.getMessage()), t);
                } else {
                    log.info("上传face++校验字符串文件, result={}", JSON.toJSONString(r));
                    requestDTO.setDelta(r.getImageUrl());
                }
            } finally {
                latch.countDown();
            }
        });
        // 等待上传完成
        try {
            latch.await();
        } catch (Exception e) {
            log.error(String.format("上传face++文件失败， exception=%s", e.getMessage()), e);
            throw new BizException(LoginAccountErrorCode.PORTRAIT_AUTH_UPLOAD_FILE_ERROR);
        }
        // 任意上传失败，返回
        if (org.apache.commons.lang3.StringUtils.isAnyBlank(requestDTO.getDelta(), requestDTO.getLiveImageUrl(), requestDTO.getFacePlusEnvImageUrl())) {
            log.error("上传face++文件失败2, delta={}, liveImage={}, envImage={}", requestDTO.getDelta(), requestDTO.getLiveImageUrl(), requestDTO.getFacePlusEnvImageUrl());
            throw new BizException(LoginAccountErrorCode.PORTRAIT_AUTH_UPLOAD_FILE_ERROR);
        }
        log.info("face++采集###请求, data={}", JSON.toJSONString(requestDTO));
        FacePlusPortraitAuthResponseDTO responseDTO = facePlusPortraitAuthDubboService.saveAuthInfo(requestDTO);
        log.info("face++采集###响应, data={}", JSON.toJSONString(responseDTO));
        PortraitAuthResponseVO vo = new PortraitAuthResponseVO();
        vo.setPortraitAuthStatus(responseDTO.getPortraitAuthStatus().getStatus());
        vo.setLeftPortraitAuthTimes(responseDTO.getRemainingTimes());
        return Result.with(vo);
    }


    @PostMapping("/smallLoanDataAuthentication")
    @ApiOperation("借款资料 — 小易贷资料认证")
    public Result<LoanDataAuthenticationResponseVO> smallLoanDataAuthentication() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("UserDataController.smallLoanDataAuthentication userId={}", userId);

        LoanDataAuthenticationResponseVO responseVO = new LoanDataAuthenticationResponseVO();
        LoanBusinessInfoDTO loanBusinessInfoDTO = loanBusinessDubboService.selectByProductType(ProjectTypeEnum.SMALL_LOAN.getValue());
        if(loanBusinessInfoDTO == null || loanBusinessInfoDTO.getIsDisplay() == 0){
            return Result.with(responseVO);
        }

        LoanDataAuthenticationRequestDTO requestDTO = new LoanDataAuthenticationRequestDTO();
        requestDTO.setUserId(userId);

        responseVO.setIsShowIncreaseTheLoanAmount(loanBusinessInfoDTO.getAuthOnOff());
        LoanDataAuthenticationResponseDTO responseDTO = userDataDubboService.loanDataAuthentication(requestDTO);
        if (responseDTO != null) {
            responseVO.setFullAuthorize(false);
            responseVO.setPersonalInfo(responseDTO.getPersonalInfo());
            responseVO.setIdentityInfoStatus(responseDTO.getIdentityInfoStatus());
            responseVO.setOperatorAuthorize(responseDTO.getOperatorAuthorize());
            responseVO.setFullAuthorize(responseDTO.getPersonalInfo() == 1
                    && (responseDTO.getIdentityInfoStatus() == 1 || responseDTO.getIdentityInfoStatus() == 4)
                    && (responseDTO.getOperatorAuthorize()== 1 || responseDTO.getOperatorAuthorize() == 2));
        }
        return Result.with(responseVO);
    }


    @PostMapping("/creditCardLoanDataAuthentication")
    @ApiOperation("借款资料 — 信用卡贷资料认证")
    public Result<LoanDataAuthenticationResponseVO> creditCardLoanDataAuthentication() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("UserDataController.creditCardLoanDataAuthentication userId={}", userId);

        LoanDataAuthenticationResponseVO responseVO = new LoanDataAuthenticationResponseVO();
        LoanBusinessInfoDTO loanBusinessInfoDTO = loanBusinessDubboService.selectByProductType(ProjectTypeEnum.CREDIT_CARD_LOAN.getValue());
        if(loanBusinessInfoDTO == null || loanBusinessInfoDTO.getIsDisplay() == 0){
            return Result.with(responseVO);
        }

        LoanDataAuthenticationRequestDTO requestDTO = new LoanDataAuthenticationRequestDTO();
        requestDTO.setUserId(userId);

        responseVO.setIsShowIncreaseTheLoanAmount(loanBusinessInfoDTO.getAuthOnOff());
        LoanDataAuthenticationResponseDTO responseDTO = userDataDubboService.loanDataAuthentication(requestDTO);
        if (responseDTO != null) {
            responseVO.setFullAuthorize(false);
            responseVO.setPersonalInfo(responseDTO.getPersonalInfo());
            responseVO.setIdentityInfoStatus(responseDTO.getIdentityInfoStatus());
            responseVO.setOperatorAuthorize(responseDTO.getOperatorAuthorize());
            responseVO.setCreditCardAuthorize(responseDTO.getCreditCardAuthorize());
            responseVO.setFullAuthorize(responseDTO.getPersonalInfo() == 1
                    && (responseDTO.getIdentityInfoStatus() == 1 || responseDTO.getIdentityInfoStatus() == 4)
                    && (responseDTO.getOperatorAuthorize() == 1 || responseDTO.getOperatorAuthorize() == 2)
                    && (responseDTO.getCreditCardAuthorize() == 1 || responseDTO.getCreditCardAuthorize() == 2));

        }
        return Result.with(responseVO);
    }

    @PostMapping("/socialSecurityLoanDataAuthentication")
    @ApiOperation("借款资料 — 社保贷资料认证")
    public Result<LoanDataAuthenticationResponseVO> socialSecurityLoanDataAuthentication() {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("UserDataController.socialSecurityLoanDataAuthentication userId={}", userId);

        LoanDataAuthenticationResponseVO responseVO = new LoanDataAuthenticationResponseVO();
        LoanBusinessInfoDTO loanBusinessInfoDTO = loanBusinessDubboService.selectByProductType(ProjectTypeEnum.SOCIAL_SECURITY_LOAN.getValue());
        if(loanBusinessInfoDTO == null || loanBusinessInfoDTO.getIsDisplay() == 0){
            return Result.with(responseVO);
        }

        LoanDataAuthenticationRequestDTO requestDTO = new LoanDataAuthenticationRequestDTO();
        requestDTO.setUserId(userId);

        responseVO.setIsShowIncreaseTheLoanAmount(loanBusinessInfoDTO.getAuthOnOff());
        LoanDataAuthenticationResponseDTO responseDTO = userDataDubboService.loanDataAuthentication(requestDTO);
        if (responseDTO != null) {
            responseVO.setFullAuthorize(false);
            responseVO.setPersonalInfo(responseDTO.getPersonalInfo());
            responseVO.setIdentityInfoStatus(responseDTO.getIdentityInfoStatus());
            responseVO.setOperatorAuthorize(responseDTO.getOperatorAuthorize());
            responseVO.setSocialSecurityOperatorAuthorize(responseDTO.getSocialSecurityOperatorAuthorize());
            responseVO.setFullAuthorize(responseDTO.getPersonalInfo() == 1
                    && (responseDTO.getIdentityInfoStatus() == 1 || responseDTO.getIdentityInfoStatus() == 4)
                    && (responseDTO.getOperatorAuthorize() == 1 || responseDTO.getOperatorAuthorize() == 2)
                    && (responseDTO.getSocialSecurityOperatorAuthorize() == 1 || responseDTO.getSocialSecurityOperatorAuthorize() == 2));
        }
        return Result.with(responseVO);
    }
    
    @PostMapping("/consumeLoanDataAuthentication")
    @ApiOperation("借款资料 — 消费贷资料认证")
    public Result<LoanDataAuthenticationResponseVO> consumeLoanDataAuthentication() {
        LoanDataAuthenticationResponseVO responseVO = new LoanDataAuthenticationResponseVO();
        
        // 查询消费贷借款业务配置
		LoanBusinessInfoDTO loanBusinessInfoDTO = loanBusinessDubboService.selectByProductType(ProjectTypeEnum.CONSUME_LOAN.getValue());
		if (loanBusinessInfoDTO == null || loanBusinessInfoDTO.getIsDisplay() == 0) {
			return Result.with(responseVO);
		}

		// 查询借款资料认证信息
        LoanDataAuthenticationRequestDTO requestDTO = new LoanDataAuthenticationRequestDTO();
        requestDTO.setUserId(PrincipalContext.getUserId());
        LoanDataAuthenticationResponseDTO responseDTO = userDataDubboService.loanDataAuthentication(requestDTO);
        if (null == responseDTO) {
        	return Result.with(responseVO);
        }
        
        // 返回结果处理
        responseVO.setIsShowIncreaseTheLoanAmount(loanBusinessInfoDTO.getAuthOnOff());        
        responseVO.setPersonalInfo(responseDTO.getPersonalInfo());
        responseVO.setIdentityInfoStatus(responseDTO.getIdentityInfoStatus());
        responseVO.setOperatorAuthorize(responseDTO.getOperatorAuthorize());
        responseVO.setTaobaoOperatorAuthorize(responseDTO.getTaobaoAuthorize());
        if (responseDTO.getPersonalInfo() == 1 
        		&& (responseDTO.getIdentityInfoStatus() == 1 || responseDTO.getIdentityInfoStatus() == 4)
                && (responseDTO.getOperatorAuthorize() == 1 || responseDTO.getOperatorAuthorize() == 2)
                && (responseDTO.getTaobaoAuthorize() == 1 || responseDTO.getTaobaoAuthorize() == 2)) {
        	responseVO.setFullAuthorize(true);
        } else {
        	responseVO.setFullAuthorize(false);
        }
        return Result.with(responseVO);
    }    

    @PostMapping("/socialSecurityIncreasesTheAmountOfLoan")
    @ApiOperation("借款资料 — 社保借提额资料认证")
    public Result<IncreaseTheLoanAmountResponseVO> socialSecurityIncreasesTheAmountOfLoan(@RequestBody @Valid IncreaseTheLoanAmountRequestVO requestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("UserDataController.socialSecurityIncreasesTheAmountOfLoan userId={}, requestVO={}", userId, JSON.toJSON(requestVO));

        LoanBusinessInfoDTO loanBusinessInfoDTO = loanBusinessDubboService.selectByProductType(ProjectTypeEnum.SOCIAL_SECURITY_LOAN.getValue());

        IncreaseTheLoanAmountRequestDTO requestDTO = new IncreaseTheLoanAmountRequestDTO();
        requestDTO.setUserId(userId);
        requestDTO.setProjectId(requestVO.getProjectId());
        //requestDTO.setAuditAmount(requestVO.getAuditAmount());

        return Result.with(this.getIncreaseTheLoanAmountResponseList(loanBusinessInfoDTO, requestDTO));
    }

    @PostMapping("/creditCardIncreasesTheAmountOfLoan")
    @ApiOperation("借款资料 — 信用卡借提额资料认证")
    public Result<IncreaseTheLoanAmountResponseVO> creditCardIncreasesTheAmountOfLoan(@RequestBody @Valid IncreaseTheLoanAmountRequestVO requestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("UserDataController.crediCardIncreasesTheAmountOfLoan userId={}, requestVO={}", userId, JSON.toJSON(requestVO));

        LoanBusinessInfoDTO loanBusinessInfoDTO = loanBusinessDubboService.selectByProductType(ProjectTypeEnum.CREDIT_CARD_LOAN.getValue());

        IncreaseTheLoanAmountRequestDTO requestDTO = new IncreaseTheLoanAmountRequestDTO();
        requestDTO.setUserId(userId);
        requestDTO.setProjectId(requestVO.getProjectId());
        //requestDTO.setAuditAmount(requestVO.getAuditAmount());

        return Result.with(this.getIncreaseTheLoanAmountResponseList(loanBusinessInfoDTO, requestDTO));
    }

    @PostMapping("/smallIncreasesTheAmountOfLoan")
    @ApiOperation("借款资料 — 小易借提额资料认证")
    public Result<IncreaseTheLoanAmountResponseVO> smallIncreasesTheAmountOfLoan(@RequestBody @Valid IncreaseTheLoanAmountRequestVO requestVO) {
        String userId = String.valueOf(PrincipalContext.getUserId());
        log.info("UserDataController.smallIncreasesTheAmountOfLoan userId={}, requestVO={}", userId, JSON.toJSON(requestVO));

        LoanBusinessInfoDTO loanBusinessInfoDTO = loanBusinessDubboService.selectByProductType(ProjectTypeEnum.SMALL_LOAN.getValue());

        IncreaseTheLoanAmountRequestDTO requestDTO = new IncreaseTheLoanAmountRequestDTO();
        requestDTO.setUserId(userId);
        requestDTO.setProjectId(requestVO.getProjectId());
        //requestDTO.setAuditAmount(requestVO.getAuditAmount());

        return Result.with(this.getIncreaseTheLoanAmountResponseList(loanBusinessInfoDTO, requestDTO));
    }
    
    @PostMapping("/consumeLoanIncreasesTheAmountOfLoan")
    @ApiOperation("借款资料 — 消费贷提额资料认证")
    public Result<IncreaseTheLoanAmountResponseVO> consumeLoanIncreasesTheAmountOfLoan(@RequestBody @Valid IncreaseTheLoanAmountRequestVO requestVO) {
    	// 查询消费贷借款业务配置
        LoanBusinessInfoDTO loanBusinessInfoDTO = loanBusinessDubboService.selectByProductType(ProjectTypeEnum.CONSUME_LOAN.getValue());
        
        IncreaseTheLoanAmountRequestDTO requestDTO = new IncreaseTheLoanAmountRequestDTO();
        requestDTO.setUserId(PrincipalContext.getUserId());
        requestDTO.setProjectId(requestVO.getProjectId());
        return Result.with(this.getIncreaseTheLoanAmountResponseList(loanBusinessInfoDTO, requestDTO));
    }

    /**
     * 区分产品返回认证类型
     */
    private IncreaseTheLoanAmountResponseVO getIncreaseTheLoanAmountResponseList(LoanBusinessInfoDTO loanBusinessInfoDTO, IncreaseTheLoanAmountRequestDTO requestDTO) {
        log.info("UserDataController loanBusinessInfoDTO={}, IncreaseTheLoanAmountRequestDTO={}", JSON.toJSON(loanBusinessInfoDTO), JSON.toJSONString(requestDTO));

        IncreaseTheLoanAmountResponseVO responseVO = new IncreaseTheLoanAmountResponseVO();
        LoanDataAuthenticationRequestDTO loanData = new LoanDataAuthenticationRequestDTO();
        loanData.setUserId(requestDTO.getUserId());

        LoanDataAuthenticationResponseDTO responseDTO = userDataDubboService.loanDataAuthentication(loanData);
        responseVO.setList(new ArrayList<>());
        if (loanBusinessInfoDTO.getAuthOnOff() == 0 || responseDTO == null) {
            return responseVO;
        }

        UserPersonalDubboInfoDTO personalInfo = userDataDubboService.userPersonalInfo(requestDTO.getUserId());
        for (IncreaseTheLoanAmountEnum amountEnum : IncreaseTheLoanAmountEnum.values()) {
            IncreaseTheLoanAmountResponseVO.IncreaseTheLoanAmount increaseTheLoanAmount = new IncreaseTheLoanAmountResponseVO.IncreaseTheLoanAmount();
            if (loanBusinessInfoDTO.getEduAuth() == 1 && IncreaseTheLoanAmountEnum.EDUCATION_AUTHORIZE == amountEnum) {
                if (personalInfo != null && !UserPersonalEnum.UserEduLevelEnum.SPECIAL_SCHOOL.getType().equals(personalInfo.getEducationLevel())) {
                    increaseTheLoanAmount.setType(IncreaseTheLoanAmountEnum.EDUCATION_AUTHORIZE.getValue());
                    increaseTheLoanAmount.setStatus(responseDTO.getEducationAuthorize());
                    increaseTheLoanAmount.setMinimumAmount(loanBusinessInfoDTO.getEduAuthLoanMinAmount());
                    increaseTheLoanAmount.setMaximumAmount(loanBusinessInfoDTO.getEduAuthLoanMaxAmount());
                    responseVO.getList().add(increaseTheLoanAmount);
                }
            }
            if (loanBusinessInfoDTO.getJdAuth() == 1 && IncreaseTheLoanAmountEnum.JD_AUTHORIZE == amountEnum) {
                increaseTheLoanAmount.setType(IncreaseTheLoanAmountEnum.JD_AUTHORIZE.getValue());
                increaseTheLoanAmount.setStatus(responseDTO.getJdAuthorize());
                increaseTheLoanAmount.setMinimumAmount(loanBusinessInfoDTO.getJdAuthLoanMinAmount());
                increaseTheLoanAmount.setMaximumAmount(loanBusinessInfoDTO.getJdAuthLoanMaxAmount());
                responseVO.getList().add(increaseTheLoanAmount);
            }
            if (loanBusinessInfoDTO.getCreditCardAuth() == 1 && IncreaseTheLoanAmountEnum.CREDIT_CARD_AUTHORIZE == amountEnum) {
                increaseTheLoanAmount.setType(IncreaseTheLoanAmountEnum.CREDIT_CARD_AUTHORIZE.getValue());
                increaseTheLoanAmount.setStatus(responseDTO.getCreditCardAuthorize());
                increaseTheLoanAmount.setMinimumAmount(loanBusinessInfoDTO.getCreditCardAuthLoanMinAmount());
                increaseTheLoanAmount.setMaximumAmount(loanBusinessInfoDTO.getCreditCardAuthLoanMaxAmount());
                responseVO.getList().add(increaseTheLoanAmount);
            }
            if (loanBusinessInfoDTO.getSocialSecurityAuth() == 1 && IncreaseTheLoanAmountEnum.SOCIAL_SECURITY_OPERATOR_AUTHORIZE == amountEnum) {
                increaseTheLoanAmount.setType(IncreaseTheLoanAmountEnum.SOCIAL_SECURITY_OPERATOR_AUTHORIZE.getValue());
                increaseTheLoanAmount.setStatus(responseDTO.getSocialSecurityOperatorAuthorize());
                increaseTheLoanAmount.setMinimumAmount(loanBusinessInfoDTO.getSocialSecurityAuthLoanMinAmount());
                increaseTheLoanAmount.setMaximumAmount(loanBusinessInfoDTO.getSocialSecurityAuthLoanMaxAmount());
                responseVO.getList().add(increaseTheLoanAmount);
            }
        }

        if (requestDTO.getProjectId() != null && requestDTO.getProjectId() != 0) {
            ProjectDTO projectDTO = projectDubboService.selectProjectById(requestDTO.getProjectId());

            boolean educationAuth = personalInfo != null
                    && !UserPersonalEnum.UserEduLevelEnum.SPECIAL_SCHOOL.getType().equals(personalInfo.getEducationLevel())
                    && (responseDTO.getEducationAuthorize() == 1 || responseDTO.getEducationAuthorize() == 2)
                    && projectDTO.getCreateTime().before(responseDTO.getEducationTime());

            boolean jdAuth = (responseDTO.getJdAuthorize() == 1 || responseDTO.getJdAuthorize() == 2)
                    && projectDTO.getCreateTime().before(responseDTO.getJdAuthTime());

            boolean creditCardAuth = (responseDTO.getCreditCardAuthorize() == 1 || responseDTO.getCreditCardAuthorize() == 2)
                    && projectDTO.getCreateTime().before(responseDTO.getCreditCardTime());

            boolean socialSecurityAuth = (responseDTO.getSocialSecurityOperatorAuthorize() == 1 || responseDTO.getSocialSecurityOperatorAuthorize() == 2)
                    && projectDTO.getCreateTime().before(responseDTO.getSocialSecurityTime());

            responseVO.setIsAuthenticated(educationAuth || jdAuth ||creditCardAuth || socialSecurityAuth);
        }

        return responseVO;
    }

    @AuthIgnore
    @PostMapping("/getCopyWritingConfiguration")
    @ApiOperation("获取后台文案配置")
    public Result<CopyWritingConfigurationResponseVO> getCopyWritingConfiguration() {
        CopyWritingConfigurationResponseVO responseVO = new CopyWritingConfigurationResponseVO();
        List<PromptMsgConfigDTO> promptMsgConfigDTOList = promptMsgConfigDubboService.selectListByPrimaryKey();
        log.info("getCopyWritingConfiguration promptMsgConfigDTOList={}", JSON.toJSONString(promptMsgConfigDTOList));

        promptMsgConfigDTOList.forEach(p -> {
            PromptMsgTypeEnum subStatusEnum = PromptMsgTypeEnum.enumOf(p.getPageId());
            if(subStatusEnum != null){
                switch (subStatusEnum){
                    case OPENLOANACCOUNTPROMPTMSG:
                        responseVO.setOpenLoanAccountPromptMsg(p.getPromptMsg());
                        break;
                    case LOANDETAIL:
                        responseVO.setLoanDetail(p.getPromptMsg());
                        break;
                    case LOANDATADETAILAMOUNTAUTH:
                        responseVO.setLoanDataDetailAmountAuth(p.getPromptMsg());
                        break;
                    case AMOUNTAUTH:
                        responseVO.setAmountAuth(p.getPromptMsg());
                        break;
                    case LOANDETAILCONFIRM:
                        responseVO.setLoanDetailConfirm(p.getPromptMsg());
                        break;
                    case LOANDETAILCONFIRMAMOUNTAUTH:
                        responseVO.setLoanDetailConfirmAmountAuth(p.getPromptMsg());
                        break;
                    case LOANDETAILMODIFYDETAIL:
                        responseVO.setLoanDetailModifyDetail(p.getPromptMsg());
                        break;
                    case AMOUNTAUTHREAPPLYLOAN:
                        responseVO.setAmountAuthReapplyLoan(p.getPromptMsg());
                        break;
                }
            }else {
                log.warn("getCopyWritingConfiguration subStatusEnum={}, promptMsgConfigDTOList={}", p.getPageId(), JSON.toJSONString(promptMsgConfigDTOList));
            }

        });
        return Result.with(responseVO);
    }

}
